#include <stdio.h>
#include "../include/transportADT.h"
#include <unistd.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

struct transportCDT{
	char creator;		//flag que indica si creo la MsgQ
	int id_msgqueue;	//file descriptor de la MsgQ a la que esta conectado el proceso
	long id;			//id del proceso
	long sendid;		//id del proceso al cual se le quiere enviar un mensaje
};

struct msgbuf{
	long idreceive;		//id del proceso que debe recibir el mensaje
	long idsend;		//id del proceso que mando el mensaje
	char mtext[MSG_LEN+1];	//buffer para el mensaje
};

transportADT
openTrans(void * id){
	int msqid;
	struct transportCDT * trans;

	//la key_t de la MsgQ es la misma que el id del su creador
	if((msqid=msgget(*((key_t *)id), 0666 | IPC_CREAT | IPC_EXCL))==-1)
		return NULL;
	if((trans=malloc(sizeof(struct transportCDT)))==NULL)
		exit(1);
	trans->creator=1;
	trans->id_msgqueue=msqid;
	trans->id=trans->sendid=*((int *)id);

	return trans;
}

transportADT
getTrans(void * id, void * dest) {
	int msqid;
	struct transportCDT * trans;

	//solo se acopla a la MsgQ, dada por la key_t del id del creador
	if((msqid=msgget(*((key_t *)dest), 0666 | IPC_CREAT))==-1)
		return NULL;
	if((trans=malloc(sizeof(struct transportCDT)))==NULL)
		exit(1);
	trans->creator=0;
	trans->id_msgqueue=msqid;
	trans->id=*((int *)id);
	trans->sendid=*((int *)dest); //destino seteado al id del creador de la MsgQ

	return trans;
}

/*
 * 	-1 error de lectura
 */
int
writeMsg(transportADT trans, const void * buf, int size){
	struct msgbuf message;

	if (size>MSG_LEN)
		return -1;

	message.idreceive=(long)trans->sendid;
	message.idsend=(long)trans->id;

	memcpy(message.mtext, (char *)buf, size);

	if(msgsnd(trans->id_msgqueue, &message, size+sizeof(long), 0)==0)
		return size;
	return -1;
}

/*
 * 	-1 error de lectura
 */
int
readMsg(transportADT trans, void * buf, int size){
	int aux;
	struct msgbuf message;

	if((aux=msgrcv(trans->id_msgqueue, &message, size+sizeof(long), trans->id, 0))==-1)
		return -1;
	memcpy((char *)buf, message.mtext, size);
	trans->sendid=message.idsend;

	return aux-sizeof(long);
}

void
closeTrans(transportADT trans){
	if(trans!=NULL) {
		if(trans->creator) { //cierra solo el creador
			msgctl(trans->id_msgqueue, IPC_RMID, NULL);
			//cierro con struct msqid_ds * igual a NULL porque
			//solo me importa cerrarla, no su estado
		}
		free(trans);
	}
}
